package com.cyx.fruit.mySSM.basedao;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

// 数据库操作的基类
public abstract class basedao<T> {
    private Class entityClass; // 声明一个反射类对象，用于保存泛型的实际类型x
    static Connection conn; // 数据库连接对象
    PreparedStatement psmt; // SQL语句处理对象
    ResultSet rs; // 结果集对象

    // 无参构造函数，获取泛型的Class对象
    public basedao() {
        // 获取当前类的带有泛型类型的父类
        Type genericSuperclass = getClass().getGenericSuperclass();
        // 获取泛型类型列表
        Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
        // 获取第一个泛型类型
        Type actualTypeArgument = actualTypeArguments[0];
        try {
            // 获取泛型类型的Class对象
            entityClass = Class.forName(actualTypeArgument.getTypeName());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    // 给占位符赋值
    private void setParams(PreparedStatement psmt, Object... params) {
        for (int i = 0; i < params.length; i++) {
            try {
                // 设置第i+1个占位符的值
                psmt.setObject(i + 1, params[i]);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

    // 给实例对象指定的属性名赋属性值
    private void setValues(Object obj, String propertyName, Object propertyValue) {
        // 获取当前对象的Class对象
        Class<?> clazz = obj.getClass();

        try {
            // 获取指定名称的属性对象
            Field declaredField = clazz.getDeclaredField(propertyName);
            // 开启属性操作权限
            declaredField.setAccessible(true);
            // 设置属性值
            declaredField.set(obj, propertyValue);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    // 获取连接对象
    protected static Connection getConn() {
        try {
            // 创建一个Properties对象，用于加载属性文件
            Properties properties = new Properties();
            // 读取属性文件
            InputStream in = basedao.class.getClassLoader().getResourceAsStream("jdbc.properties");
            properties.load(in); // 加载属性文件

            // 创建数据源
            DataSource ds = DruidDataSourceFactory.createDataSource(properties);
            // 获取连接对象
            Connection connection = ds.getConnection();

            return connection;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 关闭资源
    public void close(ResultSet rs, PreparedStatement ps, Connection conn) {
        try {
            if (rs != null) {
                rs.close(); // 关闭结果集
            }
            if (ps != null) {
                ps.close(); // 关闭语句处理对象
            }
            if (conn != null && !conn.isClosed()) {
                conn.close(); // 关闭连接对象
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    // 实现增删改操作
    /**
     * 判断SQL语句是不是insert
     * 修改和删除操作返回值执行的记录行数
     * 添加操作的返回值是自增的id值
     * @param sql SQL语句
     * @param params SQL参数
     * @return 返回受影响的行数或自增的ID
     */
    protected int executeUpdate(String sql, Object... params) {
        boolean insertFlag = sql.trim().toUpperCase().startsWith("INSERT"); // 判断是否为INSERT语句

        try {
            conn = getConn(); // 获取连接对象
            if (insertFlag) {
                // 如果是insert操作，获取自增主键
                psmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            } else {
                // 不是insert操作
                psmt = conn.prepareStatement(sql);
            }
            setParams(psmt, params); // 给占位符赋值
            int count = psmt.executeUpdate(); // 执行SQL语句

            if (insertFlag) {
                // 如果是insert操作，获取自增的主键
                rs = psmt.getGeneratedKeys();
                if (rs.next()) {
                    return ((Long) rs.getLong(1)).intValue(); // 返回自增的主键值
                }
            }
            return count; // 返回受影响的行数

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            close(rs, psmt, conn); // 关闭资源
        }
    }

    // 查询单个实体
    protected T load(String sql, Object... params) {
        try {
            conn = getConn(); // 获取连接对象
            psmt = conn.prepareStatement(sql); // 创建PreparedStatement对象
            setParams(psmt, params); // 给占位符赋值
            rs = psmt.executeQuery(); // 执行查询

            if (rs.next()) {
                T entry = (T) entityClass.getDeclaredConstructor().newInstance(); // 创建泛型类型实例对象
                ResultSetMetaData metaData = rs.getMetaData(); // 获取结果集的元数据
                int columnCount = metaData.getColumnCount(); // 获取结果集的字段数量

                for (int i = 0; i < columnCount; i++) {
                    String columName = metaData.getColumnName(i + 1); // 获取字段名
                    Object columValue = rs.getObject(i + 1); // 获取字段值
                    setValues(entry, columName, columValue); // 设置对象属性值
                }
                return entry; // 返回实体对象
            }

        } catch (SQLException | NoSuchMethodException | InstantiationException | IllegalAccessException |
                 InvocationTargetException e) {
            throw new RuntimeException(e);
        } finally {
            close(rs, psmt, conn); // 关闭资源
        }
        return null;
    }

    // 查询多个实体
    protected List<T> executeQuery(String sql, Object... params) {
        List<T> list = new ArrayList<>();
        try {
            conn = getConn(); // 获取连接对象
            psmt = conn.prepareStatement(sql); // 创建PreparedStatement对象
            setParams(psmt, params); // 给占位符赋值
            rs = psmt.executeQuery(); // 执行查询

            ResultSetMetaData metaData = rs.getMetaData(); // 获取结果集的元数据
            int columnCount = metaData.getColumnCount(); // 获取结果集的字段数量

            while (rs.next()) {
                T entry = (T) entityClass.newInstance(); // 创建泛型类型实例对象
                for (int i = 0; i < columnCount; i++) {
                    String columnName = metaData.getColumnName(i + 1); // 获取字段名
                    Object columnValue = rs.getObject(i + 1); // 获取字段值
                    setValues(entry, columnName, columnValue); // 设置对象属性值
                }
                list.add(entry); // 将实体对象添加到列表中
            }
            return list; // 返回实体对象列表
        } catch (SQLException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        } finally {
            close(rs, psmt, conn); // 关闭资源
        }
    }

    // 复杂查询(带SQL函数的查询): 将查询结果存入一个数组
    protected Object[] executeComplexQuery(String sql, Object... params) {
        try {
            conn = getConn(); // 获取连接对象
            psmt = conn.prepareStatement(sql); // 创建PreparedStatement对象
            setParams(psmt, params); // 给占位符赋值
            rs = psmt.executeQuery(); // 执行查询

            ResultSetMetaData metaData = rs.getMetaData(); // 获取结果集的元数据
            int columnCount = metaData.getColumnCount(); // 获取结果集的字段数量

            Object[] columnValueArr = new Object[columnCount]; // 创建一个数组，存放查询结果

            if (rs.next()) {
                for (int i = 0; i < columnCount; i++) {
                    Object objectValue = rs.getObject(i + 1); // 从结果集中取每个字段值
                    columnValueArr[i] = objectValue; // 将字段值存入数组
                }
            }
            return columnValueArr; // 返回查询结果数组
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            close(rs, psmt, conn); // 关闭资源
        }
    }
}
